home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / TEMP / GNU / flex / Startcondi < prev    next >
Text File  |  1995-06-28  |  10KB  |  392 lines

  1. Start conditions
  2. Previous: <Generated scanner=>Generateds> * Next: <Multiple buffers=>Multiplebu> * Up: <Top=>!Root>
  3.  
  4. #Wrap on
  5. {fH3}Start conditions{f}
  6.  
  7. {fCode}flex{f} provides a mechanism for conditionally activating
  8. rules.  Any rule whose pattern is prefixed with "<sc>"
  9. will only be active when the scanner is in the start
  10. condition named "sc".  For example,
  11.  
  12. #Wrap off
  13. #fCode
  14. <STRING>[^"]\*        \{ \/\* eat up the string body ... \*\/
  15.             …
  16.             \}
  17. #f
  18. #Wrap on
  19.  
  20. will be active only when the scanner is in the "STRING"
  21. start condition, and
  22.  
  23. #Wrap off
  24. #fCode
  25. <INITIAL,STRING,QUOTE>\\.        \{ \/\* handle an escape ... \*\/
  26.             …
  27.             \}
  28. #f
  29. #Wrap on
  30.  
  31. will be active only when the current start condition is
  32. either "INITIAL", "STRING", or "QUOTE".
  33.  
  34. Start conditions are declared in the definitions (first)
  35. section of the input using unindented lines beginning with
  36. either {fEmphasis}%s{f} or {fEmphasis}%x{f} followed by a list of names.  The former
  37. declares {fEmphasis}inclusive{f} start conditions, the latter {fEmphasis}exclusive{f}
  38. start conditions.  A start condition is activated using
  39. the {fCode}BEGIN{f} action.  Until the next {fCode}BEGIN{f} action is
  40. executed, rules with the given start condition will be active
  41. and rules with other start conditions will be inactive.
  42. If the start condition is {fEmphasis}inclusive{f}, then rules with no
  43. start conditions at all will also be active.  If it is
  44. {fEmphasis}exclusive{f}, then {fEmphasis}only{f} rules qualified with the start
  45. condition will be active.  A set of rules contingent on the
  46. same exclusive start condition describe a scanner which is
  47. independent of any of the other rules in the {fCode}flex{f} input.
  48. Because of this, exclusive start conditions make it easy
  49. to specify "mini-scanners" which scan portions of the
  50. input that are syntactically different from the rest
  51. (e.g., comments).
  52.  
  53. If the distinction between inclusive and exclusive start
  54. conditions is still a little vague, here's a simple
  55. example illustrating the connection between the two.  The set
  56. of rules:
  57.  
  58. #Wrap off
  59. #fCode
  60. %s example
  61. %%
  62.  
  63. <example>foo   do\_something();
  64.  
  65. bar            something\_else();
  66. #f
  67. #Wrap on
  68.  
  69. is equivalent to
  70.  
  71. #Wrap off
  72. #fCode
  73. %x example
  74. %%
  75.  
  76. <example>foo   do\_something();
  77.  
  78. <INITIAL,example>bar    something\_else();
  79. #f
  80. #Wrap on
  81.  
  82. Without the {fEmphasis}<INITIAL,example>{f} qualifier, the {fEmphasis}bar{f} pattern
  83. in the second example wouldn't be active (i.e., couldn't match) when
  84. in start condition {fEmphasis}example{f}.  If we just used {fEmphasis}<example>{f}
  85. to qualify {fEmphasis}bar{f}, though, then it would only be active in
  86. {fEmphasis}example{f} and not in {fCode}INITIAL{f}, while in the first example
  87. it's active in both, because in the first example the {fEmphasis}example{f}
  88. starting condition is an {fEmphasis}inclusive{f} ({fEmphasis}%s{f}) start condition.
  89.  
  90. Also note that the special start-condition specifier {fEmphasis}<\*>{f}
  91. matches every start condition.  Thus, the above example
  92. could also have been written;
  93.  
  94. #Wrap off
  95. #fCode
  96. %x example
  97. %%
  98.  
  99. <example>foo   do\_something();
  100.  
  101. <\*>bar    something\_else();
  102. #f
  103. #Wrap on
  104.  
  105. The default rule (to {fEmphasis}ECHO{f} any unmatched character) remains
  106. active in start conditions.  It is equivalent to:
  107.  
  108. #Wrap off
  109. #fCode
  110. <\*>.|\\\\n     ECHO;
  111. #f
  112. #Wrap on
  113.  
  114. {fEmphasis}BEGIN(0){f} returns to the original state where only the
  115. rules with no start conditions are active.  This state can
  116. also be referred to as the start-condition "INITIAL", so
  117. {fEmphasis}BEGIN(INITIAL){f} is equivalent to {fEmphasis}BEGIN(0){f}.  (The
  118. parentheses around the start condition name are not required but
  119. are considered good style.)
  120.  
  121. {fCode}BEGIN{f} actions can also be given as indented code at the
  122. beginning of the rules section.  For example, the
  123. following will cause the scanner to enter the "SPECIAL" start
  124. condition whenever {fEmphasis}yylex(){f} is called and the global
  125. variable {fCode}enter\_special{f} is true:
  126.  
  127. #Wrap off
  128. #fCode
  129.         int enter\_special;
  130.  
  131. %x SPECIAL
  132. %%
  133.         if ( enter\_special )
  134.             BEGIN(SPECIAL);
  135.  
  136. <SPECIAL>blahblahblah
  137. …more rules follow…
  138. #f
  139. #Wrap on
  140.  
  141. To illustrate the uses of start conditions, here is a
  142. scanner which provides two different interpretations of a
  143. string like "123.456".  By default it will treat it as as
  144. three tokens, the integer "123", a dot ('.'), and the
  145. integer "456".  But if the string is preceded earlier in
  146. the line by the string "expect-floats" it will treat it as
  147. a single token, the floating-point number 123.456:
  148.  
  149. #Wrap off
  150. #fCode
  151. %\{
  152. \#include <math.h>
  153. %\}
  154. %s expect
  155.  
  156. %%
  157. expect-floats        BEGIN(expect);
  158.  
  159. <expect>[0-9]+"."[0-9]+      \{
  160.             printf( "found a float, = %f\\n",
  161.                     atof( yytext ) );
  162.             \}
  163. <expect>\\n           \{
  164.             \/\* that's the end of the line, so
  165.              \* we need another "expect-number"
  166.              \* before we'll recognize any more
  167.              \* numbers
  168.              \*\/
  169.             BEGIN(INITIAL);
  170.             \}
  171.  
  172. [0-9]+      \{
  173.  
  174. Version 2.5               December 1994                        18
  175.  
  176.             printf( "found an integer, = %d\\n",
  177.                     atoi( yytext ) );
  178.             \}
  179.  
  180. "."         printf( "found a dot\\n" );
  181. #f
  182. #Wrap on
  183.  
  184. Here is a scanner which recognizes (and discards) C
  185. comments while maintaining a count of the current input line.
  186.  
  187. #Wrap off
  188. #fCode
  189. %x comment
  190. %%
  191.         int line\_num = 1;
  192.  
  193. "\/\*"         BEGIN(comment);
  194.  
  195. <comment>[^\*\\n]\*        \/\* eat anything that's not a '\*' \*\/
  196. <comment>"\*"+[^\*\/\\n]\*   \/\* eat up '\*'s not followed by '\/'s \*\/
  197. <comment>\\n             ++line\_num;
  198. <comment>"\*"+"\/"        BEGIN(INITIAL);
  199. #f
  200. #Wrap on
  201.  
  202. This scanner goes to a bit of trouble to match as much
  203. text as possible with each rule.  In general, when
  204. attempting to write a high-speed scanner try to match as
  205. much possible in each rule, as it's a big win.
  206.  
  207. Note that start-conditions names are really integer values
  208. and can be stored as such.  Thus, the above could be
  209. extended in the following fashion:
  210.  
  211. #Wrap off
  212. #fCode
  213. %x comment foo
  214. %%
  215.         int line\_num = 1;
  216.         int comment\_caller;
  217.  
  218. "\/\*"         \{
  219.              comment\_caller = INITIAL;
  220.              BEGIN(comment);
  221.              \}
  222.  
  223.  
  224. <foo>"\/\*"    \{
  225.              comment\_caller = foo;
  226.              BEGIN(comment);
  227.              \}
  228.  
  229. <comment>[^\*\\n]\*        \/\* eat anything that's not a '\*' \*\/
  230. <comment>"\*"+[^\*\/\\n]\*   \/\* eat up '\*'s not followed by '\/'s \*\/
  231. <comment>\\n             ++line\_num;
  232. <comment>"\*"+"\/"        BEGIN(comment\_caller);
  233. #f
  234. #Wrap on
  235.  
  236. Furthermore, you can access the current start condition
  237. using the integer-valued {fCode}YY\_START{f} macro.  For example, the
  238. above assignments to {fCode}comment\_caller{f} could instead be
  239. written
  240.  
  241. #Wrap off
  242. #fCode
  243. comment\_caller = YY\_START;
  244. #f
  245. #Wrap on
  246.  
  247. Flex provides {fCode}YYSTATE{f} as an alias for {fCode}YY\_START{f} (since that
  248. is what's used by AT&T {fCode}lex{f}).
  249.  
  250. Note that start conditions do not have their own
  251. name-space; %s's and %x's declare names in the same fashion as
  252. \#define's.
  253.  
  254. Finally, here's an example of how to match C-style quoted
  255. strings using exclusive start conditions, including
  256. expanded escape sequences (but not including checking for
  257. a string that's too long):
  258.  
  259. #Wrap off
  260. #fCode
  261. %x str
  262.  
  263. %%
  264.         char string\_buf[MAX\_STR\_CONST];
  265.         char \*string\_buf\_ptr;
  266.  
  267. \\"      string\_buf\_ptr = string\_buf; BEGIN(str);
  268.  
  269. <str>\\"        \{ \/\* saw closing quote - all done \*\/
  270.         BEGIN(INITIAL);
  271.         \*string\_buf\_ptr = '\\0';
  272.         \/\* return string constant token type and
  273.          \* value to parser
  274.          \*\/
  275.         \}
  276.  
  277. <str>\\n        \{
  278.         \/\* error - unterminated string constant \*\/
  279.         \/\* generate error message \*\/
  280.         \}
  281.  
  282. <str>\\\\[0-7]\{1,3\} \{
  283.         \/\* octal escape sequence \*\/
  284.         int result;
  285.  
  286.         (void) sscanf( yytext + 1, "%o", &result );
  287.  
  288.         if ( result > 0xff )
  289.                 \/\* error, constant is out-of-bounds \*\/
  290.  
  291.         \*string\_buf\_ptr++ = result;
  292.         \}
  293.  
  294. <str>\\\\[0-9]+ \{
  295.         \/\* generate error - bad escape sequence; something
  296.          \* like '\\48' or '\\0777777'
  297.          \*\/
  298.         \}
  299.  
  300. <str>\\\\n  \*string\_buf\_ptr++ = '\\n';
  301. <str>\\\\t  \*string\_buf\_ptr++ = '\\t';
  302. <str>\\\\r  \*string\_buf\_ptr++ = '\\r';
  303. <str>\\\\b  \*string\_buf\_ptr++ = '\\b';
  304. <str>\\\\f  \*string\_buf\_ptr++ = '\\f';
  305.  
  306. <str>\\\\(.|\\n)  \*string\_buf\_ptr++ = yytext[1];
  307.  
  308. <str>[^\\\\\\n\\"]+        \{
  309.         char \*yptr = yytext;
  310.  
  311.         while ( \*yptr )
  312.                 \*string\_buf\_ptr++ = \*yptr++;
  313.         \}
  314. #f
  315. #Wrap on
  316.  
  317. Often, such as in some of the examples above, you wind up
  318. writing a whole bunch of rules all preceded by the same
  319. start condition(s).  Flex makes this a little easier and
  320. cleaner by introducing a notion of start condition {fUnderline}scope{f}.
  321. A start condition scope is begun with:
  322.  
  323. #Wrap off
  324. #fCode
  325. <SCs>\{
  326. #f
  327. #Wrap on
  328.  
  329. where SCs is a list of one or more start conditions.
  330. Inside the start condition scope, every rule automatically
  331. has the prefix {fEmphasis}<SCs>{f} applied to it, until a {fEmphasis}\}{f} which
  332. matches the initial {fEmphasis}\{{f}.  So, for example,
  333.  
  334. #Wrap off
  335. #fCode
  336. <ESC>\{
  337.     "\\\\n"   return '\\n';
  338.     "\\\\r"   return '\\r';
  339.     "\\\\f"   return '\\f';
  340.     "\\\\0"   return '\\0';
  341. \}
  342. #f
  343. #Wrap on
  344.  
  345. is equivalent to:
  346.  
  347. #Wrap off
  348. #fCode
  349. <ESC>"\\\\n"  return '\\n';
  350. <ESC>"\\\\r"  return '\\r';
  351. <ESC>"\\\\f"  return '\\f';
  352. <ESC>"\\\\0"  return '\\0';
  353. #f
  354. #Wrap on
  355.  
  356. Start condition scopes may be nested.
  357.  
  358. Three routines are available for manipulating stacks of
  359. start conditions:
  360.  
  361. #Indent +4
  362. #Indent
  363. {fEmphasis}void yy\_push\_state(int new\_state){f}
  364. #Indent +4
  365. pushes the current start condition onto the top of
  366. the start condition stack and switches to {fStrong}new\_state{f}
  367. as though you had used {fEmphasis}BEGIN new\_state{f} (recall that
  368. start condition names are also integers).
  369.  
  370. #Indent
  371. {fEmphasis}void yy\_pop\_state(){f}
  372. #Indent +4
  373. pops the top of the stack and switches to it via
  374. {fCode}BEGIN{f}.
  375.  
  376. #Indent
  377. {fEmphasis}int yy\_top\_state(){f}
  378. #Indent +4
  379. returns the top of the stack without altering the
  380. stack's contents.
  381.  
  382. #Indent
  383.  
  384. The start condition stack grows dynamically and so has no
  385. built-in size limitation.  If memory is exhausted, program
  386. execution aborts.
  387.  
  388. To use start condition stacks, your scanner must include a
  389. {fEmphasis}%option stack{f} directive (see Options below).
  390.  
  391.